extra credit

4 views
Skip to first unread message

RxRick

unread,
Nov 6, 2009, 12:46:07 PM11/6/09
to cw-android
I desperately need to learn how to populate a Spinner from an sqlite
db.

pg 37 "see what the activity looks like if you use a Spinner instead
of a ListView", yes I would love to know how.

Please, can you provide some sample code. I can't get it, am very new
to all this Java stuff. Some sample code instead of 'extra credit'
would be some much more helpful to us dummies.

I've search far and wide on the 'net. Everybody has a different
approach. It would be nice if you would take the wonderful classes you
spelled out in Chapter 12, and show how to populate a Spinner instead
of a List View.

Please, I'm about to pull my hair out.

Mark Murphy

unread,
Nov 6, 2009, 12:55:39 PM11/6/09
to cw-an...@googlegroups.com
RxRick wrote:
> I desperately need to learn how to populate a Spinner from an sqlite
> db.
>
> pg 37 "see what the activity looks like if you use a Spinner instead
> of a ListView", yes I would love to know how.
>
> Please, can you provide some sample code. I can't get it, am very new
> to all this Java stuff. Some sample code instead of 'extra credit'
> would be some much more helpful to us dummies.

AFAIK, it is exactly the same as populating a ListView from a SQLite
database, except:

1. You put a Spinner widget in the layout instead of a ListView

2. You call setDropDownResource() on your adapter to define the layout
to be used when the user is making a choice from the Spinner

3. You use Spinner-friendly layouts with the adapter, such as
android.R.layout.simple_spinner_item in the constructor and
android.R.layout.simple_spinner_dropdown_item in the
setDropDownResource() call

I have never used a Spinner with SQLite, simply because if there is
enough data to warrant SQLite, there is too much data to use with a
Spinner, IMHO.

> Please, I'm about to pull my hair out.

Speaking as a follicle-ly challenged individual, I cannot recommend this
practice. ;-)

--
Mark Murphy (a Commons Guy)
http://commonsware.com | http://twitter.com/commonsguy

Android App Developer Books: http://commonsware.com/books

RxRick

unread,
Nov 7, 2009, 8:46:10 AM11/7/09
to cw-android
Thanks Mark.

I'm trying to port an application that I've been supporting for 25
years, and I've re-written for 5 other platforms (dos/windows/palm os/
windows mobile/webapp). Maybe if i can get this java stuff down, I'll
only have one code base to maintain :) wishful thinking?

You're probably right, it's not data enough to warrant sqlite, but i
want to learn sqlite for another portion of the application. Thought
I'd start out with the simplest, most basic function the application
performs, pulling up a list of drug model names and populating a
spinner (which is called a dropdown list in every other platform).

My problem is, I'm not anywhere near grasping the basic coding
concepts behind Android Java. I can follow it up to a point and then..
lost. At this point I can't tell the difference between a 'reserved'
word and a name you're using for a variable.

In the 6 books I'm reading, every author uses ListView in their
example code. And then says something like, spinner is the same. Well
no, it isn't.

Sorry, I should have supplied the code that is stumping me.

in onCreate I have these lines:
// open Model Database
dbModel=(new PkmodelSQLiteHelper(this)).getWritableDatabase();
Spinner list=(Spinner)findViewById(R.id.cboModel);
model=Pkmodel.getModelNames(dbModel);
startManagingCursor(model);

adapter=new ModelAdapter(model);
list.setAdapter(adapter);
list.setOnItemClickListener(onModelClick);

I have this class inside main:
// Pkmodel database
class PkmodelWrapper {
private TextView Drug=null;
private View row=null;

PkmodelWrapper(View row){
this.row=row;
}

void populateFrom(Cursor c){
getDrug().setText(c.getString(c.getColumnIndex("Drug")));
}

TextView getDrug() {
if (Drug==null){
// TO DO
}
return(Drug);
}

}

And here is the class where I'm stumped, in the newView function. I'm
trying to adapt your newView code from a ListView adapter to a Spinner
adapter:

// Adapter for cboModel
class ModelAdapter extends CursorAdapter {
ModelAdapter(Cursor c) {
super(Main.this, c);
}

@Override
public void bindView(View row, Context ctxt, Cursor c) {
PkmodelWrapper wrapper=(PkmodelWrapper)row.getTag();
wrapper.populateFrom(c);
}

-----------> here is where I'm lost:

@Override
public View newView(Context ctxt, Cursor c, ViewGroup parent) {
ArrayAdapter<String> adapterForSpinner;
adapterForSpinner = new ArrayAdapter<String>
(this,android.R.layout.simple_spinner_item);
adapterForSpinner.setDropDownViewResource
(android.R.layout.simple_spinner_dropdown_item);
cboModel.setAdapter(adapterForSpinner);

PkmodelWrapper wrapper = new PkmodelWrapper(row);
row.setTag(wrapper);
wrapper.populateFrom(c);
return(row);
}
}

Mark Murphy

unread,
Nov 7, 2009, 9:04:29 AM11/7/09
to cw-an...@googlegroups.com
RxRick wrote:
> My problem is, I'm not anywhere near grasping the basic coding
> concepts behind Android Java. I can follow it up to a point and then..
> lost. At this point I can't tell the difference between a 'reserved'
> word and a name you're using for a variable.

I *definitely* would learn Java basics first outside of Android.

> In the 6 books I'm reading, every author uses ListView in their
> example code. And then says something like, spinner is the same. Well
> no, it isn't.

By and large, it is. Your problem isn't with Spinner, near as I can
tell. It's with CursorAdapter, and secondarily with a sub-optimal tutorial.

> And here is the class where I'm stumped, in the newView function. I'm
> trying to adapt your newView code from a ListView adapter to a Spinner
> adapter:
>
> // Adapter for cboModel
> class ModelAdapter extends CursorAdapter {
> ModelAdapter(Cursor c) {
> super(Main.this, c);
> }
>
> @Override
> public void bindView(View row, Context ctxt, Cursor c) {
> PkmodelWrapper wrapper=(PkmodelWrapper)row.getTag();
> wrapper.populateFrom(c);
> }
>
> -----------> here is where I'm lost:
>
> @Override
> public View newView(Context ctxt, Cursor c, ViewGroup parent) {
> ArrayAdapter<String> adapterForSpinner;
> adapterForSpinner = new ArrayAdapter<String>
> (this,android.R.layout.simple_spinner_item);
> adapterForSpinner.setDropDownViewResource
> (android.R.layout.simple_spinner_dropdown_item);
> cboModel.setAdapter(adapterForSpinner);
>
> PkmodelWrapper wrapper = new PkmodelWrapper(row);
> row.setTag(wrapper);
> wrapper.populateFrom(c);
> return(row);
> }
> }

Just have newView() inflate a new row:

@Override
public View newView(Context ctxt, Cursor c, ViewGroup parent) {

LayoutInflater inflater=getLayoutInflater();
View row=inflater.inflate(R.layout.whateveryoucallit, parent, false);
PkmodelWrapper wrapper=new PkmodelWrapper(row);

row.setTag(wrapper);

return(row);
}

(substituting in the proper layout ID for whatever your custom layout is
for the drop-down resource)

After newView() returns, bindView() will be called to pour the contents
of your Cursor into that row.

Now, _Android Programming Tutorials_, tutorial #12, step #6 shows
newView() doing the binding as well. At the time I wrote that tutorial,
I thought newView() was also responsible for binding, which it isn't.
The next version of the book (should be available in digital form by the
end of the year) will correct that. What's in the tutorial isn't wrong,
per se, but it is redundant and unnecessary.

Android Consulting/App Development: http://commonsware.com/consulting

RxRick

unread,
Nov 7, 2009, 10:11:54 AM11/7/09
to cw-android
Thanks Mark. Hurray, no errors in Eclipse now.

I thought inflater was something specific to ListView, I
misinterpreted p 41 'inflate the layout as needed for rows'. I
couldn't find a definition in the Android reference or any books.
guessing it is a java dB related function?

yes.. so.. much.. to.. learn..

I'm reading some java books too, Head First Java seems the most
accessible, any others you would recommend? The basic concepts are
easy to grasp. But then they start peeling apart the onion, the
devil's in the details. And these strange four letter words - void,
super, this - that I have no clue about :) I'm determined to learn
though.

Yes, I should have subscribed online instead of buying your book
through Amazon, kicking myself now. But there's something about having
a book open on your desk, you can quickly flip back through without
losing your place (not a fan of eBooks).

Thanks again.
> Mark Murphy (a Commons Guy)http://commonsware.com|http://twitter.com/commonsguy

Mark Murphy

unread,
Nov 7, 2009, 10:39:32 AM11/7/09
to cw-an...@googlegroups.com
RxRick wrote:
> I thought inflater was something specific to ListView, I
> misinterpreted p 41 'inflate the layout as needed for rows'. I
> couldn't find a definition in the Android reference or any books.
> guessing it is a java dB related function?

getLayoutInflater() is a method on Activity, I believe. inflate() is a
method on LayoutInflater.

> I'm reading some java books too, Head First Java seems the most
> accessible, any others you would recommend?

I learned Java long enough ago that I think the books I used were
written on papyrus. But _Head First Java_ seems to be the best-reviewed
of the current crop.

> Yes, I should have subscribed online instead of buying your book
> through Amazon, kicking myself now.

Don't do that -- it might leave bruises that would be tough to explain. ;-)

--

Android 1.6 Programming Books: http://commonsware.com/books

RxRick

unread,
Nov 7, 2009, 3:17:25 PM11/7/09
to cw-android
lol. I found LayoutInflater with a search of the android docs, missed
it the first time. works with the XML layout, that makes sense now.
thanks again.

On Nov 7, 9:39 am, Mark Murphy <mmur...@commonsware.com> wrote:
> RxRick wrote:
> > I thought inflater was something specific to ListView, I
> > misinterpreted p 41 'inflate the layout as needed for rows'. I
> > couldn't find a definition in the Android reference or any books.
> > guessing it is a java dB related function?
>
> getLayoutInflater() is a method on Activity, I believe. inflate() is a
> method on LayoutInflater.
>
> > I'm reading some java books too, Head First Java seems the most
> > accessible, any others you would recommend?
>
> I learned Java long enough ago that I think the books I used were
> written on papyrus. But _Head First Java_ seems to be the best-reviewed
> of the current crop.
>
> > Yes, I should have subscribed online instead of buying your book
> > through Amazon, kicking myself now.
>
> Don't do that -- it might leave bruises that would be tough to explain. ;-)
>
> --
> Mark Murphy (a Commons Guy)http://commonsware.com|http://twitter.com/commonsguy

RxRick

unread,
Nov 9, 2009, 2:21:49 AM11/9/09
to cw-android
well, i did get eclipse to like my code, but emulator keeps saying
"sorry! app has stopped unexpectedly".

the logcat reads:
ERROR/AndroidRuntime(747): Caused by:
java.lang.IllegalArgumentException: column '_id' does not exist
at android.database.AbstractCursor.getColumnIndexOrThrow
(AbstractCursor.java:314)
at android.widget.CursorAdapter.init(CursorAdapter.java:111)
at android.widget.CursorAdapter.<init>(CursorAdapter.java:90)
at rxkinetics.abpk.Main$ModelAdapter.<init>(Main.java:173)
at rxkinetics.abpk.Main.onCreate(Main.java:91)

I opened DDMS and pulled the db from the emulator file system and
looked at it with SQLite Database Browser. The db does contain the
'_id' column, and all the data is exactly as it should be. So, it must
be my read code.

I am adapting from your List example to use with a Spinner. I'm trying
to pull out one column from each row to populate the Spinner, the
column is named 'Drug' and it contains text. The spinner is named
'cboModel'.

Does anything in my code pop out as wrong?


// Adapter for cboModel
class ModelAdapter extends CursorAdapter {
ModelAdapter(Cursor c) {
super(Main.this, c);
}

@Override
public void bindView(View row, Context ctxt, Cursor c) {
PkmodelWrapper wrapper=(PkmodelWrapper)row.getTag();
wrapper.populateFrom(c);
}

@Override
public View newView(Context ctxt, Cursor c, ViewGroup parent) {
LayoutInflater inflater=getLayoutInflater();
View row=inflater.inflate(R.id.cboModel, parent, false);

PkmodelWrapper wrapper = new PkmodelWrapper(row);
row.setTag(wrapper);
wrapper.populateFrom(c);
return(row);
}
}

// Pkmodel database
class PkmodelWrapper {
private TextView Drug=null;
private View row=null;

PkmodelWrapper(View row){
this.row=row;
}

void populateFrom(Cursor c){
getDrug().setText(c.getString(c.getColumnIndex("Drug")));
}

TextView getDrug() {
if (Drug==null){
Drug=(TextView)row.findViewById(R.id.cboModel);
}
return(Drug);

Mark Murphy

unread,
Nov 9, 2009, 7:56:18 AM11/9/09
to cw-an...@googlegroups.com
RxRick wrote:
> well, i did get eclipse to like my code, but emulator keeps saying
> "sorry! app has stopped unexpectedly".
>
> the logcat reads:
> ERROR/AndroidRuntime(747): Caused by:
> java.lang.IllegalArgumentException: column '_id' does not exist
> at android.database.AbstractCursor.getColumnIndexOrThrow
> (AbstractCursor.java:314)
> at android.widget.CursorAdapter.init(CursorAdapter.java:111)
> at android.widget.CursorAdapter.<init>(CursorAdapter.java:90)
> at rxkinetics.abpk.Main$ModelAdapter.<init>(Main.java:173)
> at rxkinetics.abpk.Main.onCreate(Main.java:91)
>
> I opened DDMS and pulled the db from the emulator file system and
> looked at it with SQLite Database Browser. The db does contain the
> '_id' column, and all the data is exactly as it should be. So, it must
> be my read code.

Make sure your query is including the _id column.

Also, a slight optimization: the value of c.getColumnIndex("Drug") will
not change in the lifetime of a Cursor, so you might see if you can
cache it somehow.

--

_Android Programming Tutorials_ Version 1.0 Available!

RxRick

unread,
Nov 9, 2009, 10:22:29 AM11/9/09
to cw-android
thank you. yes, my sql did not include '_id' column (was "SELECT Drug
FROM pkmodels ORDER BY Drug").

so, now it errors out in this line:
//throws resource not found error
//View row=inflater.inflate(R.id.cboModel, parent, false);

a few messages ago you suggested:
"View row=inflater.inflate(R.layout.whateveryoucallit, parent,
false);"
with
"Substituting in the proper layout ID for whatever your custom
layout is for the drop-down resource."

I now understand that R.id points to individual widgets within an
inflated layout. R.id values have no meaning outside the context of a
specific layout.

So, putting back in the original:
View row=inflater.inflate(R.layout.row, parent, false);
Eclipse gives a syntax error "cannot be resolved", and so with this
line:
View row=inflater.inflate(R.layout.simple_spinner_dropdown_item,
parent, false);

R.layout points to layout resources. i think i need to set the drop
down resource, but not sure how. my brain needs examples to connect
concept to code, all the examples at developer.android.com use an
array adapter. i have yet to grasp the most basic fundamentals of how
these parts all work together, so it's back to the books.

thanks again.
> Mark Murphy (a Commons Guy)http://commonsware.com|http://twitter.com/commonsguy

RxRick

unread,
Nov 18, 2009, 10:03:23 AM11/18/09
to cw-android
I was able to get Eclipse to like my code by changing this line:
View row=inflater.inflate(R.layout.simple_spinner_dropdown_item,
parent, false);

to this:
View row=inflater.inflate
(android.R.layout.simple_spinner_dropdown_item, parent, false);

So, I run it through the emulator, and now it stops with this error:

Uncaught handler: thread main exiting due to uncaught exception
java.lang.NullPointerException
at rxkinetics.abpk.Main$PkmodelWrapper.populateFrom(Main.java:
207)
at rxkinetics.abpk.Main$ModelAdapter.newView(Main.java:192)
at android.widget.CursorAdapter.getView(CursorAdapter.java:182)

Here are my classes. Per your previous advice 'After newView()
returns, bindView() will be called to pour the contents
of your Cursor into that row". Apparently it errors out before
bindView. Any advice on where to start tracking down the source of the
NullPointerException error?

class ModelAdapter extends CursorAdapter {
ModelAdapter(Cursor c) {
super(Main.this, c);
}

@Override
public void bindView(View row, Context ctxt, Cursor c) {
PkmodelWrapper wrapper=(PkmodelWrapper)row.getTag();
wrapper.populateFrom(c);
}

@Override
public View newView(Context ctxt, Cursor c, ViewGroup parent) {
LayoutInflater inflater=getLayoutInflater();
View row=inflater.inflate
(android.R.layout.simple_spinner_dropdown_item, parent, false);

PkmodelWrapper wrapper = new PkmodelWrapper(row);
row.setTag(wrapper);
wrapper.populateFrom(c);
return(row);
}
}

// Pkmodel database
class PkmodelWrapper {
private TextView Drug=null;
private View row=null;

PkmodelWrapper(View row){
this.row=row;
}

void populateFrom(Cursor c){
getDrug().setText(c.getString(c.getColumnIndex("Drug")));
}

TextView getDrug() {
if (Drug==null){
Drug=(TextView)row.findViewById(R.id.cboModel);
}
return(Drug);
}

}




Mark Murphy

unread,
Nov 18, 2009, 10:17:15 AM11/18/09
to cw-an...@googlegroups.com
RxRick wrote:
> So, I run it through the emulator, and now it stops with this error:
>
> Uncaught handler: thread main exiting due to uncaught exception
> java.lang.NullPointerException
> at rxkinetics.abpk.Main$PkmodelWrapper.populateFrom(Main.java:
> 207)
> at rxkinetics.abpk.Main$ModelAdapter.newView(Main.java:192)
> at android.widget.CursorAdapter.getView(CursorAdapter.java:182)
>
> Here are my classes. Per your previous advice 'After newView()
> returns, bindView() will be called to pour the contents
> of your Cursor into that row". Apparently it errors out before
> bindView. Any advice on where to start tracking down the source of the
> NullPointerException error?

I'd start at line 207 of Main.java.

> void populateFrom(Cursor c){
> getDrug().setText(c.getString(c.getColumnIndex("Drug")));
> }

Since we know the exception is in populateFrom(), and this is the only
line, we know the NullPointerException is here. And, we know that the
exception is not somewhere deeper in Android code -- it's right here.
That means either getDrug() is returning null, or c is null.

> TextView getDrug() {
> if (Drug==null){
> Drug=(TextView)row.findViewById(R.id.cboModel);
> }
> return(Drug);
> }

So now we know that either:

-- c in populateFrom() is null, or
-- there is no widget named @+id/cboModel in your row layout, or
-- there is such a widget, but Android's build tools are confused

To eliminate the latter, try a Project > Force Clean in Eclipse, or
otherwise get rid of the contents of your gen/ and bin/ directories.
Then try rebuilding and re-running. I'm not aware of Eclipse getting
confused as frequently as the command-line tools do, though.

The other two, you'll need to investigate.

Also, since we're starting to get waaaaaaaaaaaaaaaaaay outside the scope
of the books, it would be best if you posted questions like this up on
StackOverflow (in the #android tag) or on [android-developers]. I am
trying to keep this list focused on supporting the CommonsWare books,
sample code, open source code, etc.

--
Warescription: Three Android Books, Plus Updates, $35/Year

RxRick

unread,
Nov 18, 2009, 11:45:04 AM11/18/09
to cw-android
Thanks for all your help.

It all boils down to me trying to adapt your code when I don't even
begin to comprehend all the nested classes and wrappers and adapters
and all that complexity.

I deleted it all and went with the sample code in the Android dev
docs, and it works just fine:
dbModel=(new PkmodelSQLiteHelper(this)).getWritableDatabase();
model=Pkmodel.getAll(dbModel);
startManagingCursor(model);

Spinner list=(Spinner)findViewById(R.id.cboModel);

SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
android.R.layout.simple_spinner_item, // Use a template
that displays a text view
model, // Give the cursor to the list adapter
new String[] {"Drug"}, // Map the NAME column in the
people database to
new int[] {android.R.id.text1}); // The "text1" view
defined in the XML template

adapter.setDropDownViewResource
(android.R.layout.simple_spinner_dropdown_item);
list.setAdapter(adapter);

Sorry to have taken up so much of your time on this discussion group.

Thanks again for all your help.
> Mark Murphy (a Commons Guy)http://commonsware.com|http://twitter.com/commonsguy
Reply all
Reply to author
Forward
0 new messages